package server

import (
	"context"
	"sync"

	"gitee.com/hasika/common-server/dispatcher"
	"gitee.com/hasika/common-server/idispatcher"
	"gitee.com/hasika/common-server/option"
	"gitee.com/hasika/common-server/runtime_server"
	"gitee.com/hasika/common-server/session"
)

var sessionManager *session.Manager

func GetSessionManager() *session.Manager {
	return sessionManager
}

type Server struct {
	option         *option.ServiceOption
	sessionManager *session.Manager
	ctx            context.Context
	cancel         context.CancelFunc
	servers        []runtime_server.IRuntimeServer
	stopOnce       sync.Once
	dispatcher     idispatcher.MessageDispatcher
}

func NewServer(option *option.ServiceOption, parentCtx context.Context) *Server {
	ctx, cancel := context.WithCancel(parentCtx)
	manager := session.NewManager(option)
	sessionManager = manager
	s := &Server{option: option, ctx: ctx, cancel: cancel, sessionManager: manager, dispatcher: dispatcher.NewDefaultDispatcher(option, sessionManager)}
	return s
}

func (s *Server) GetSessionManager() *session.Manager {
	return s.sessionManager
}

func (s *Server) Start() {
	for _, listenOption := range s.option.GetListenOptions() {
		runTimeServer := s.StartListenAndServe(s.ctx, listenOption, s.dispatcher)
		s.servers = append(s.servers, runTimeServer)
	}
}

func (s *Server) Stop() {
	s.stopOnce.Do(func() {
		before := s.option.BeforeStopCallback()
		if before != nil {
			before()
		}
		s.cancel()
		for _, rs := range s.servers {
			rs.Stop()
		}
		post := s.option.PostStopCallback()
		if post != nil {
			post()
		}
	})
}
